﻿using Grow.Json;
using Grow.Module.Service;
using Grow.Utils.Exceptions;
using System.Text;

namespace Grow.Rest.Http
{
    public class RestClient : IRestClient, IDisposable
    {
        private readonly IJsonContext _jsonContext;
        private readonly IHttpClientFactory _httpClientFactory;

        private HttpTypeEnum restClientHttpType;
        private readonly Dictionary<string, string> restClientHeaders;
        private readonly Dictionary<string, string> restClientParameters;
        private object? restClientBody;

        public RestClient(IServiceContext serviceContext)
        {
            _jsonContext = serviceContext.GetRequiredService<IJsonContext>();

            _httpClientFactory = serviceContext.GetRequiredService<IHttpClientFactory>();

            restClientHttpType = HttpTypeEnum.Get;

            restClientHeaders = new();

            restClientParameters = new();
        }
        public IRestClient SetHttpType(HttpTypeEnum httpType)
        {
            restClientHttpType = httpType;
            return this;
        }

        public IRestClient AddHeader(string key, string value)
        {
            restClientHeaders[key] = value;
            return this;
        }

        public IRestClient AddParameter(string key, string value)
        {

            restClientParameters[key] = value;
            return this;
        }


        public IRestClient AddBody(object? body)
        {
            restClientBody = body;
            return this;
        }


        public async Task<IRestClientResponse> SendAsync(string url, CancellationToken cancellationToken)
        {
            HttpResponseMessage httpResponseMessage = await GetHttpResponseMessageAsync(url, cancellationToken);

            string responseJson = await httpResponseMessage.Content.ReadAsStringAsync(cancellationToken);

            return !httpResponseMessage.IsSuccessStatusCode
                ? throw new GrowHttpException($"Http is erro:{responseJson}")
                : (IRestClientResponse)new RestClientResponse(httpResponseMessage.Headers);
        }

        public async Task<IRestClientResponse<TData>> SendAsync<TData>(string url, CancellationToken cancellationToken)
        {
            HttpResponseMessage httpResponseMessage = await GetHttpResponseMessageAsync(url, cancellationToken);

            string responseJson = await httpResponseMessage.Content.ReadAsStringAsync(cancellationToken);

            return !httpResponseMessage.IsSuccessStatusCode
                ? throw new GrowHttpException($"Http is erro:{responseJson}")
                : (IRestClientResponse<TData>)new RestClientResponse<TData>(await _jsonContext.DeserializeAsync<TData>(responseJson, cancellationToken), httpResponseMessage.Headers);
        }




        private async Task<HttpResponseMessage> GetHttpResponseMessageAsync(string url, CancellationToken cancellationToken)
        {
            HttpClient httpClient = _httpClientFactory.CreateClient();

            HttpMethod httpMethod = restClientHttpType switch
            {
                HttpTypeEnum.Get => HttpMethod.Get,
                HttpTypeEnum.Post => HttpMethod.Post,
                HttpTypeEnum.Put => HttpMethod.Put,
                HttpTypeEnum.Patch => HttpMethod.Patch,
                HttpTypeEnum.Delete => HttpMethod.Delete,
                _ => HttpMethod.Get,
            };
            HttpRequestMessage httpRequestMessage = new(httpMethod, url);

            if (restClientBody is not null)
            {
                string requestJson = await _jsonContext.SerializeAsync(restClientBody, cancellationToken);

                httpRequestMessage.Content = new StringContent(requestJson, Encoding.UTF8, "application/json");
            }

            if (restClientHeaders.Count > 0)
            {

                foreach (KeyValuePair<string, string> restClientHeader in restClientHeaders)
                {
                    httpRequestMessage.Headers.Add(restClientHeader.Key, restClientHeader.Value);
                }
            }

            HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, cancellationToken);
            return httpResponseMessage;
        }

        #region Dispose
        private bool disposedValue;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    restClientHeaders.Clear();
                    restClientParameters.Clear();
                }

                // TODO: 释放未托管的资源(未托管的对象)并重写终结器
                // TODO: 将大型字段设置为 null
                disposedValue = true;
            }
        }

        // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
        // ~RestClient()
        // {
        //     // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
        //     Dispose(disposing: false);
        // }

        public void Dispose()
        {
            // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }




        #endregion


    }
}